#include "GEnginePCH.h"
#include "Shaders.h"
#include "Support.h"

namespace Shaders
{
	LPDIRECT3DVERTEXDECLARATION9 pVertexDeclaration[10];
	LPDIRECT3DVERTEXSHADER9 pVertexShader[10];
	LPDIRECT3DPIXELSHADER9 pPixelShader[10];
	int nrVS=0, nrPS=0, nrVD=0;



LPDIRECT3DVERTEXDECLARATION9& getVertexDeclaration(int index)
{
	return pVertexDeclaration[index];
}
LPDIRECT3DVERTEXSHADER9& getVertexShader(int index)
{
	return pVertexShader[index];
}
LPDIRECT3DPIXELSHADER9& getPixelShader(int index)
{
	return pPixelShader[index];
}
void CreateVertexDeclaration()
{
	// First, we create the vertex declaration
	D3DVERTEXELEMENT9 VertexElements0 [] =
	{
		// The first element describes the position
		{
			0,						// Stream
				0,						// Byte offset
				D3DDECLTYPE_FLOAT3,		// Information format
				D3DDECLMETHOD_DEFAULT,	// No additional processing done by Tesselator
				D3DDECLUSAGE_POSITION,	// Information semantics (this is the position)
				0						// Usage index
		},

		// The second element describes the texture coordinates
		{
			0,						// Stream
				12,						// 12-byte offset (the first 12 bytes are occupied by the position information)
				D3DDECLTYPE_FLOAT2,		// Information format
				D3DDECLMETHOD_DEFAULT,	// No additional processing done by Tesselator
				D3DDECLUSAGE_TEXCOORD,	// Information semantics (these are the texture coordinates)
				0						// Usage index
			},

			D3DDECL_END()				// This marks the end of the vertex element declaration list (mandatory)
	};
	D3DVERTEXELEMENT9 VertexElements1 [] = {
		{ 0, 0,  D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
		{ 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR,    0 },
		{ 0, 16, D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
		{ 0, 24, D3DDECLTYPE_FLOAT1,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_PSIZE, 0 },
		D3DDECL_END()	
	};
	D3DVERTEXELEMENT9 VertexElements2[] = 
	{
		{0, 0,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
		{0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
		{0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
		D3DDECL_END()
	};	
	D3DVERTEXELEMENT9 VertexElements3 [] = {
		{ 0, 0,  D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
		{ 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR,    0 },
		D3DDECL_END()	
	};
	D3DVERTEXELEMENT9 VertexElements4 [] = {
		{ 0, 0,  D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
		D3DDECL_END()	
	};
	if (FAILED(d3ddev->CreateVertexDeclaration(VertexElements0, &pVertexDeclaration[0])))
		MessBox("Error! Could not create the vertex declaration 0");
	if (FAILED(d3ddev->CreateVertexDeclaration(VertexElements1, &pVertexDeclaration[1])))
		MessBox("Error! Could not create the vertex declaration 1");
	if (FAILED(d3ddev->CreateVertexDeclaration(VertexElements2, &pVertexDeclaration[2])))
		MessBox("Error! Could not create the vertex declaration 2");
	if (FAILED(d3ddev->CreateVertexDeclaration(VertexElements3, &pVertexDeclaration[3])))
		MessBox("Error! Could not create the vertex declaration 3");
	if (FAILED(d3ddev->CreateVertexDeclaration(VertexElements4, &pVertexDeclaration[4])))
		MessBox("Error! Could not create the vertex declaration 4");
	nrVD = 5;
}
// Load shader support data
void LoadData( LPSTR ShaderFile, LPSTR ShaderName, LPSTR ShaderVersion, bool IsVertexShader, int index, bool assembled)
{
	LPD3DXBUFFER pCode = NULL, pErrors = NULL;
	bool hasFailed = false;
	if(assembled == true)
	{
		if( FAILED( D3DXAssembleShaderFromFile(
			ShaderFile,						// Shader input file
			NULL,							// No additional macro information
			NULL,							// No additional include information
			D3DXSHADER_DEBUG,	// Compilation flag (pack matrices as Row-Major)
			&pCode,							// Compiled shader code
			&pErrors						// List of compilation errors / warnings
			) ) )
		{
			hasFailed=true;
		}
	}
	else
	{
		// First, we compile the shader source code
		if (FAILED(D3DXCompileShaderFromFile
			(
			ShaderFile,						// Shader input file
			NULL,							// No additional macro information
			NULL,							// No additional include information
			ShaderName,						// The name of the shader function
			ShaderVersion,					// The shader profile
			D3DXSHADER_DEBUG,//D3DXSHADER_PACKMATRIX_ROWMAJOR,	// Compilation flag (pack matrices as Row-Major)
			&pCode,							// Compiled shader code
			&pErrors,						// List of compilation errors / warnings
			NULL							// Constant table is not used here
			)))
		{
			hasFailed=true;
		}
	}
	if(hasFailed==true)
	{
		char errs[500]="\0";
		if(assembled==false)
		{
			strcpy_s(errs,(char*)pErrors->GetBufferPointer());
		}
		if (IsVertexShader)
		{
			char c[300];
			sprintf_s(c,"Error! Could not compile vertex shader %d . \n %s",index,errs);
			MessBox(c);
		}
		else
		{	
			char c[300];
			sprintf_s(c,"Error! Could not compile pixel shader %d . \n %s",index,errs);
			MessBox(c);
		}
		return;
	}

	if (IsVertexShader)
	{
		if (FAILED(d3ddev->CreateVertexShader
			(
			(DWORD *)pCode->GetBufferPointer(),		// The compiled shader data
			&pVertexShader[index]							// The generated vertex shader
			)))
		{
			char c[300];
			sprintf_s(c,"Error! Could not create the vertex shader %d . \n ",index);
			MessBox(c);
		}
		else 
		{
			nrVS++;
		}
	}
	else
	{
		if (FAILED(d3ddev->CreatePixelShader
			(
			(DWORD *)pCode->GetBufferPointer(), 
			&pPixelShader[index]
			)))
		{
			char c[300];
			sprintf_s(c,"Error! Could not create the pixel shader %d . \n ",index);
			MessBox(c);
		}
		else 
		{
			nrPS++;
		}
	}
}

void Init()
{
	CreateVertexDeclaration();
	LoadData( "../data/LowLevelVS1.vsh", "MainVertexShader", "vs_2_0", true, 0, true);
	LoadData( "../data/GVertexShader1.fx", "MainVertexShader", "vs_2_0", true, 1, false);
	LoadData( "../data/GVertexShader2.fx", "SecondaryVertexShader", "vs_2_0", true, 2, false);
	LoadData( "../data/GVertexShader3.fx", "ThirdVertexShader", "vs_2_0", true, 3, false);
	LoadData( "../data/GVertexShader4.fx", "FourthVertexShader", "vs_2_0", true, 4, false);
	
	LoadData( "../data/LowLevelPS1.psh", "MainPixelShader", "ps_2_0", false, 0, true);	
	LoadData( "../data/GPixelShader1.fx", "MainPixelShader", "ps_2_0", false, 1, false);	
	LoadData( "../data/GPixelShader2.fx", "SecondaryPixelShader", "ps_2_0", false, 2, false);
	LoadData( "../data/GPixelShader3.fx", "ThirdPixelShader", "ps_2_0", false, 3, false);
	LoadData( "../data/GPixelShader4.fx", "FourthPixelShader", "ps_2_0", false, 4, false);
	LoadData( "../data/GPixelShader5.fx", "FifthPixelShader", "ps_2_0", false, 5, false);
}
void invalidateDeviceObjects(void)
{

	for(int i = 0; i < nrVD; i++)
	{
		if( pVertexDeclaration[i] != NULL )
		{
			int nNewRefCount = pVertexDeclaration[i]->Release();

			if( nNewRefCount > 0 )
			{
				static char strError[255];
				sprintf_s( strError, "The VertexDeclaration %d object failed to cleanup properly.\n"
					"Release() returned a reference count of %d", i, nNewRefCount );
				MessageBox( NULL, strError, "ERROR", MB_OK | MB_ICONEXCLAMATION );
			}

			pVertexDeclaration[i] = NULL;
		}
	}
	for(int i = 0; i < nrPS; i++)
	{
		if( pPixelShader[i] != NULL )
		{
			int nNewRefCount = pPixelShader[i]->Release();

			if( nNewRefCount > 0 )
			{
				static char strError[255];
				sprintf_s( strError, "The PixelShader%d object failed to cleanup properly.\n"
					"Release() returned a reference count of %d", i, nNewRefCount );
				MessageBox( NULL, strError, "ERROR", MB_OK | MB_ICONEXCLAMATION );
			}

			pPixelShader[i] = NULL;
		}
	}
	for(int i = 0; i < nrVS; i++)
	{
		if( pVertexShader[i]  != NULL )
		{
			int nNewRefCount = pVertexShader[i]->Release();

			if( nNewRefCount > 0 )
			{
				static char strError[255];
				sprintf_s( strError, "The VertexShader%d object failed to cleanup properly.\n"
					"Release() returned a reference count of %d", i, nNewRefCount );
				MessageBox( NULL, strError, "ERROR", MB_OK | MB_ICONEXCLAMATION );
			}

			pVertexShader[i] = NULL;
		}
	}
}


}